using System;
using System.Collections.Generic;
using JetBrains.CommonControls;
using JetBrains.Metadata.Reader.API;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.TaskRunnerFramework;
using JetBrains.ReSharper.UnitTestExplorer;
using JetBrains.Shell;
using JetBrains.UI.TreeView;
using JetBrains.Util.DataStructures.TreeModel;

namespace JamesKovacs.ReSharper.UnitTestSupport.VstsUnit {
    [UnitTestProvider]
    internal class VstsUnitTestProvider : IUnitTestProvider {
        private static readonly VstsUnitTestPresenter s_TestPresenter = new VstsUnitTestPresenter();

        public VstsUnitTestProvider() {
            VstsUnitSetup.Initialize();
        }

        public int CompareUnitTestElements(UnitTestElement x, UnitTestElement y) {
            if(Equals(x, y)) {
                return 0;
            }
            int compare = StringComparer.CurrentCultureIgnoreCase.Compare(x.GetTypeClrName(), y.GetTypeClrName());
            if(compare != 0) {
                return compare;
            }
            if((x is VstsUnitTestElement) && (y is VstsUnitTestFixtureElement)) {
                return -1;
            }
            if((y is VstsUnitTestElement) && (x is VstsUnitTestFixtureElement)) {
                return 1;
            }
            if((x is VstsUnitTestFixtureElement) && (y is VstsUnitTestFixtureElement)) {
                return 0;
            }
            VstsUnitTestElement xe = (VstsUnitTestElement)x;
            VstsUnitTestElement ye = (VstsUnitTestElement)y;
            return xe.Order.CompareTo(ye.Order);
        }

        public UnitTestElement Deserialize(ISolution solution, string elementString) {
            return null;
        }

        public void ExploreAssembly(IMetadataAssembly assembly, IProject project, UnitTestElementConsumer consumer) {
            new VstsAssemblyExplorer(this, consumer, assembly, project).Explore();
        }

        public void ExploreExternal(UnitTestElementConsumer consumer) {
        }

        public void ExploreFile(IFile psiFile, UnitTestElementLocationConsumer consumer, CheckForInterrupt interrupted) {
            if(psiFile == null) {
                throw new ArgumentNullException("psiFile");
            }
            psiFile.ProcessDescendants(new VstsFileExplorer(this, consumer, psiFile, interrupted));
        }

        public void ExploreSolution(ISolution solution, UnitTestElementConsumer consumer) {
        }

        public RemoteTaskRunnerInfo GetTaskRunnerInfo() {
            return new RemoteTaskRunnerInfo(typeof(VstsUnitTaskRunner));
        }

        public IList<UnitTestTask> GetTaskSequence(UnitTestElement element, IList<UnitTestElement> explicitElements) {
            VstsUnitElementBase vstsUnitElement = element as VstsUnitElementBase;
            if(vstsUnitElement == null) {
                throw new ArgumentException(string.Format("element is not VstsUnit: '{0}'", element));
            }
            return vstsUnitElement.GetTaskSequence(explicitElements);
        }

        public bool IsUnitTestElement(IDeclaredElement element) {
            ITypeElement typeElement = element as ITypeElement;
            if((typeElement != null) && VstsUnitTestInspector.IsTestFixture(typeElement)) {
                return true;
            }
            ITypeMember typeMember = element as ITypeMember;
            if(typeMember != null) {
                typeElement = typeMember.GetContainingType();
                if(((typeElement != null) && VstsUnitTestInspector.IsTestFixture(typeElement)) && VstsUnitTestInspector.IsTestMethod(typeMember)) {
                    return true;
                }
            }
            return false;
        }

        public void Present(UnitTestElement element, IPresentableItem presentableItem, TreeModelNode node, PresentationState state) {
            s_TestPresenter.UpdateItem(element, node, presentableItem, state);
        }

        public void ProfferConfiguration(TaskExecutorConfiguration configuration, UnitTestSession session) {
        }

        public string Serialize(UnitTestElement element) {
            return null;
        }

        public string ID {
            get { return "VstsUnit"; }
        }
    }
}